package com.demo.lengthFieldBasedFrameDecoder.demo2;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

public class NewServerChannelInitializer extends ChannelInitializer<SocketChannel> {

    private  final int MAX_FRAME_LENGTH;

    private  final int LENGTH_FIELD_LENGTH;

    private  final int LENGTH_FIELD_OFFSET;

    private  final int LENGTH_ADJUSTMENT;

    private  final int INITIAL_BYTES_TO_STRIP;

    public NewServerChannelInitializer(int MAX_FRAME_LENGTH,
                                       int LENGTH_FIELD_LENGTH,
                                       int LENGTH_FIELD_OFFSET,
                                       int LENGTH_ADJUSTMENT,
                                       int INITIAL_BYTES_TO_STRIP) {
        this.MAX_FRAME_LENGTH = MAX_FRAME_LENGTH;
        this.LENGTH_FIELD_LENGTH = LENGTH_FIELD_LENGTH;
        this.LENGTH_FIELD_OFFSET = LENGTH_FIELD_OFFSET;
        this.LENGTH_ADJUSTMENT = LENGTH_ADJUSTMENT;
        this.INITIAL_BYTES_TO_STRIP = INITIAL_BYTES_TO_STRIP;
    }

    @Override

    protected void initChannel(SocketChannel socketChannel) throws Exception {
        ChannelPipeline pipeline = socketChannel.pipeline();
        pipeline.addLast(new NewDecoder(MAX_FRAME_LENGTH,LENGTH_FIELD_LENGTH,LENGTH_FIELD_OFFSET,LENGTH_ADJUSTMENT,INITIAL_BYTES_TO_STRIP,false));
        // 自己的逻辑Handler
        pipeline.addLast("handler", new NewServerHandler());
    }

    /**
     * 真解码器，避免半包和联保问题。
     */
    static class NewDecoder extends LengthFieldBasedFrameDecoder {
        /**
         * 我们在Message类中定义了type和length，这都放在消息头部
         * type占1个字节，length占4个字节所以头部总长度是5个字节
         */
        private static final int HEADER_SIZE = 5;
        private byte type;
        private int length;
        private String msgBody;
        /**
         *
         * @param maxFrameLength   网络字节序，默认为最大端字节序
         * @param lengthFieldOffset 消息中长度字段偏移的字节数
         * @param lengthFieldLength 数据帧的最大长度，包含了header,长度字节，内容长度
         * @param lengthAdjustment 该字段加内容长度字段等于数据帧的长度，数据帧+这个数，就是内容长度
         * @param initialBytesToStrip 从数据帧中跳过的字节数
         * @param failFast 如果为true，则表示读取到长度域，TA的值的超过maxFrameLength，就抛出一个 TooLongFrameException

         */
        public NewDecoder(int maxFrameLength, int lengthFieldOffset,

                          int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip,

                          boolean failFast) {
            super(maxFrameLength, lengthFieldOffset, lengthFieldLength,
                    lengthAdjustment, initialBytesToStrip, failFast);
        }

        @Override

        protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
            if(in == null){
                return null;
            }
            if(in.readableBytes() < HEADER_SIZE){
                throw new Exception("错误的消息");
            }
            /**
             * 通过源码我们能看到在读的过程中
             * 每读一次读过的字节即被抛弃
             * 即指针会往前跳
             */
            type = in.readByte();
            length = in.readByte();
            if(in.readableBytes() < length){
                throw new Exception("消息不正确");
            }
            ByteBuf buf = in.readBytes(length);
            byte[] b = new byte[buf.readableBytes()];
            buf.readBytes(b);
            msgBody = new String(b,"UTF-8");
            Message msg = new Message(type,length,msgBody);
            return msg;
        }
    }
    static class NewServerHandler extends SimpleChannelInboundHandler<Object> {
        @Override
        protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object o) throws Exception {
            if(o instanceof Message) {
                Message msg = (Message)o;
                System.out.println("Client->Server:"+channelHandlerContext.channel().remoteAddress()+" send "+msg.getMsgBody());
            }
        }
    }
}
